#include "../http/HttpServer.h"
#include "../curl/CurlClient.h"
#include "../http/HttpData.h"
#include "../common/global.h"
#include "../common/CCReactor.h"
#include <iostream>
#include <string>
#include <thread>
#include <chrono>
#include <vector>
#include <atomic>
#include <iomanip>
#include <sstream>
#include <memory>

class PerformanceTest {
public:
    PerformanceTest() : server_running(false), client_count(0) {}
    
    bool SetupServer() {
        std::cout << "Setting up performance test server..." << std::endl;
        
        // Initialize reactor
        g_reactor->Init();
        g_reactor->Start();
        
        // Create server (C++11 compatible)
        server.reset(new HttpServer());
        
        // Set up performance test handler
        auto handler = [this](uint32_t handle, stHttpRequest&& req) -> int {
            request_count++;
            
            // Create response
            stHttpResponse resp;
            resp.state = 200;
            resp.heads["Content-Type"] = "application/json";
            resp.heads["Server"] = "HttpLib/1.0";
            resp.heads["Connection"] = "keep-alive";
            
            // Simple JSON response
            std::ostringstream json_stream;
            json_stream << "{\"status\": \"ok\", \"request_id\": " << request_count 
                       << ", \"method\": \"" << req.method 
                       << "\", \"url\": \"" << req.url << "\"}";
            resp.body = json_stream.str();
            
            // Send response
            server->Response(handle, std::move(resp));
            return 0;
        };
        
        // Start server
        int result = server->Start("127.0.0.1", 8082, handler);
        if (result != 0) {
            std::cerr << "Failed to start performance test server" << std::endl;
            return false;
        }
        
        server_running = true;
        std::cout << "Performance test server started on http://127.0.0.1:8082" << std::endl;
        
        // Wait for server to be ready
        std::this_thread::sleep_for(std::chrono::milliseconds(100));
        
        return true;
    }
    
    void TestServerPerformance() {
        std::cout << "\n=== Server Performance Test ===" << std::endl;
        
        if (!server_running) {
            std::cerr << "Server not running" << std::endl;
            return;
        }
        
        int num_requests = 1000;
        int num_threads = 10;
        
        std::cout << "Running server performance test..." << std::endl;
        std::cout << "Requests: " << num_requests << std::endl;
        std::cout << "Threads: " << num_threads << std::endl;
        
        auto start_time = std::chrono::high_resolution_clock::now();
        
        std::vector<std::thread> threads;
        std::atomic<int> completed_requests(0);
        
        for (int i = 0; i < num_threads; i++) {
            threads.emplace_back([this, &completed_requests, num_requests, num_threads, i]() {
                int requests_per_thread = num_requests / num_threads;
                
                for (int j = 0; j < requests_per_thread; j++) {
                    // Simulate request processing
                    stHttpRequest req;
                    req.method = "GET";
                    req.url = "/perf_test";
                    req.heads["User-Agent"] = "PerfTest";
                    
                    // Create response (simulating server processing)
                    stHttpResponse resp;
                    resp.state = 200;
                    resp.heads["Content-Type"] = "application/json";
                    resp.body = "{\"test\": \"data\", \"thread\": " + std::to_string(i) + "}";
                    
                    completed_requests++;
                }
            });
        }
        
        // Wait for all threads to complete
        for (auto& thread : threads) {
            thread.join();
        }
        
        auto end_time = std::chrono::high_resolution_clock::now();
        auto duration = std::chrono::duration_cast<std::chrono::milliseconds>(end_time - start_time);
        
        double requests_per_second = (num_requests * 1000.0) / duration.count();
        double avg_time_per_request = duration.count() * 1000.0 / num_requests;
        
        std::cout << "Results:" << std::endl;
        std::cout << "  Total time: " << duration.count() << " ms" << std::endl;
        std::cout << "  Requests per second: " << std::fixed << std::setprecision(2) << requests_per_second << std::endl;
        std::cout << "  Average time per request: " << std::fixed << std::setprecision(2) << avg_time_per_request << " μs" << std::endl;
        std::cout << "  Completed requests: " << completed_requests.load() << std::endl;
    }
    
    void TestClientPerformance() {
        std::cout << "\n=== Client Performance Test ===" << std::endl;
        
        // Create client
        // Create client (C++11 compatible)
        std::unique_ptr<CurlClient> client(new CurlClient());
        if (!client->Initialize()) {
            std::cerr << "Failed to initialize client" << std::endl;
            return;
        }
        
        int num_requests = 100;
        std::cout << "Running client performance test..." << std::endl;
        std::cout << "Requests: " << num_requests << std::endl;
        
        auto start_time = std::chrono::high_resolution_clock::now();
        
        for (int i = 0; i < num_requests; i++) {
            stHttpRequest req;
            req.method = "GET";
            req.url = "http://httpbin.org/get";
            req.heads["User-Agent"] = "PerfTest";
            req.heads["X-Request-Id"] = std::to_string(i);
            
            stHttpResponse resp;
            int result = client->Request(std::move(req), resp);
            
            if (result != 0) {
                std::cerr << "Request " << i << " failed" << std::endl;
            }
        }
        
        auto end_time = std::chrono::high_resolution_clock::now();
        auto duration = std::chrono::duration_cast<std::chrono::milliseconds>(end_time - start_time);
        
        double requests_per_second = (num_requests * 1000.0) / duration.count();
        double avg_time_per_request = duration.count() * 1000.0 / num_requests;
        
        std::cout << "Results:" << std::endl;
        std::cout << "  Total time: " << duration.count() << " ms" << std::endl;
        std::cout << "  Requests per second: " << std::fixed << std::setprecision(2) << requests_per_second << std::endl;
        std::cout << "  Average time per request: " << std::fixed << std::setprecision(2) << avg_time_per_request << " μs" << std::endl;
    }
    
    void TestConcurrentConnections() {
        std::cout << "\n=== Concurrent Connections Test ===" << std::endl;
        
        if (!server_running) {
            std::cerr << "Server not running" << std::endl;
            return;
        }
        
        int num_connections = 50;
        int requests_per_connection = 10;
        
        std::cout << "Running concurrent connections test..." << std::endl;
        std::cout << "Connections: " << num_connections << std::endl;
        std::cout << "Requests per connection: " << requests_per_connection << std::endl;
        
        auto start_time = std::chrono::high_resolution_clock::now();
        
        std::vector<std::thread> threads;
        std::atomic<int> completed_connections(0);
        
        for (int i = 0; i < num_connections; i++) {
            threads.emplace_back([this, &completed_connections, requests_per_connection, i]() {
                // Simulate connection handling
                for (int j = 0; j < requests_per_connection; j++) {
                    stHttpRequest req;
                    req.method = "GET";
                    req.url = "/concurrent_test";
                    req.heads["User-Agent"] = "ConcurrentTest";
                    req.heads["X-Connection-Id"] = std::to_string(i);
                    req.heads["X-Request-Id"] = std::to_string(j);
                    
                    // Simulate processing
                    stHttpResponse resp;
                    resp.state = 200;
                    resp.heads["Content-Type"] = "application/json";
                    resp.body = "{\"connection\": " + std::to_string(i) + ", \"request\": " + std::to_string(j) + "}";
                }
                
                completed_connections++;
            });
        }
        
        // Wait for all threads to complete
        for (auto& thread : threads) {
            thread.join();
        }
        
        auto end_time = std::chrono::high_resolution_clock::now();
        auto duration = std::chrono::duration_cast<std::chrono::milliseconds>(end_time - start_time);
        
        int total_requests = num_connections * requests_per_connection;
        double requests_per_second = (total_requests * 1000.0) / duration.count();
        double avg_time_per_request = duration.count() * 1000.0 / total_requests;
        
        std::cout << "Results:" << std::endl;
        std::cout << "  Total time: " << duration.count() << " ms" << std::endl;
        std::cout << "  Requests per second: " << std::fixed << std::setprecision(2) << requests_per_second << std::endl;
        std::cout << "  Average time per request: " << std::fixed << std::setprecision(2) << avg_time_per_request << " μs" << std::endl;
        std::cout << "  Completed connections: " << completed_connections.load() << std::endl;
    }
    
    void TestMemoryUsage() {
        std::cout << "\n=== Memory Usage Test ===" << std::endl;
        
        int num_objects = 10000;
        
        std::cout << "Testing memory usage with " << num_objects << " objects..." << std::endl;
        
        auto start_time = std::chrono::high_resolution_clock::now();
        
        // Create many HTTP objects
        std::vector<stHttpRequest> requests;
        std::vector<stHttpResponse> responses;
        
        for (int i = 0; i < num_objects; i++) {
            stHttpRequest req;
            req.method = "GET";
            req.url = "/memory_test";
            req.heads["User-Agent"] = "MemoryTest";
            req.heads["X-Test-Id"] = std::to_string(i);
            req.body = "Test data " + std::to_string(i);
            
            stHttpResponse resp;
            resp.state = 200;
            resp.heads["Content-Type"] = "text/plain";
            resp.body = "Response data " + std::to_string(i);
            
            requests.push_back(std::move(req));
            responses.push_back(std::move(resp));
        }
        
        auto end_time = std::chrono::high_resolution_clock::now();
        auto duration = std::chrono::duration_cast<std::chrono::milliseconds>(end_time - start_time);
        
        std::cout << "Results:" << std::endl;
        std::cout << "  Total time: " << duration.count() << " ms" << std::endl;
        std::cout << "  Objects created: " << num_objects << std::endl;
        std::cout << "  Memory per request: ~" << (sizeof(stHttpRequest) + sizeof(stHttpResponse)) << " bytes" << std::endl;
        
        // Clear memory
        requests.clear();
        responses.clear();
        
        std::cout << "  Memory cleared" << std::endl;
    }
    
    void Cleanup() {
        if (server_running) {
            std::cout << "\nCleaning up performance test..." << std::endl;
            g_reactor->Stop();
            server_running = false;
        }
    }
    
private:
    std::unique_ptr<HttpServer> server;
    bool server_running;
    std::atomic<int> request_count;
    std::atomic<int> client_count;
};

int main() {
    std::cout << "HTTP Library Performance Test Suite" << std::endl;
    
    PerformanceTest perf_test;
    
    // Run performance tests
    try {
        if (perf_test.SetupServer()) {
            perf_test.TestServerPerformance();
            perf_test.TestConcurrentConnections();
            perf_test.TestMemoryUsage();
        }
        
        perf_test.TestClientPerformance();
        
        std::cout << "\nAll performance tests completed!" << std::endl;
        
    } catch (const std::exception& e) {
        std::cerr << "Performance test failed with exception: " << e.what() << std::endl;
    }
    
    perf_test.Cleanup();
    
    return 0;
}